Skip to content

feat: support --json#150

Merged
Loongphy merged 3 commits into
mainfrom
agent/json-api-mode
Jul 18, 2026
Merged

feat: support --json#150
Loongphy merged 3 commits into
mainfrom
agent/json-api-mode

Conversation

@Loongphy

@Loongphy Loongphy commented Jul 14, 2026

Copy link
Copy Markdown
Owner

Summary

  • Add structured JSON output for list, switch, and remove while keeping their human-facing CLI behavior aligned.
  • Return selector-resolution details and keep multi-account removal atomic when any selector is ambiguous or missing.
  • Expose display-ready plan and usage data, including refresh request/status/source metadata needed by the GUI.
  • Canonicalize Team/Business input as Business and migrate the released registry schema 3 format to the final schema 4 format.

Why

The GUI and CLI ship together and need one stable command contract. The CLI now owns plan normalization and workflow decisions, so JSON consumers receive final product semantics instead of reimplementing backend-value interpretation.

@Loongphy

Copy link
Copy Markdown
Owner Author

@greptile review

@pkg-pr-new

pkg-pr-new Bot commented Jul 14, 2026

Copy link
Copy Markdown

Open in StackBlitz

@loongphy/codex-auth-darwin-arm64

npx https://pkg.pr.new/@loongphy/codex-auth-darwin-arm64@26b6c00

@loongphy/codex-auth-darwin-x64

npx https://pkg.pr.new/@loongphy/codex-auth-darwin-x64@26b6c00

@loongphy/codex-auth-linux-arm64

npx https://pkg.pr.new/@loongphy/codex-auth-linux-arm64@26b6c00

@loongphy/codex-auth-linux-x64

npx https://pkg.pr.new/@loongphy/codex-auth-linux-x64@26b6c00

@loongphy/codex-auth-win32-arm64

npx https://pkg.pr.new/@loongphy/codex-auth-win32-arm64@26b6c00

@loongphy/codex-auth-win32-x64

npx https://pkg.pr.new/@loongphy/codex-auth-win32-x64@26b6c00

@loongphy/codex-auth

npx https://pkg.pr.new/@loongphy/codex-auth@26b6c00

commit: 26b6c00

@greptile-apps

greptile-apps Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds a --json flag to list, switch, and remove, emitting a stable, versioned JSON document to stdout. It also canonicalises Team/Business backend values to the internal .business plan type and introduces a schema-version–gated migration path (parseStoredPlanType) so registries at v3 are normalised on load while v4 registries use strict matching.

  • New src/cli/json_output.zig and src/workflows/results.zig own all structured-output serialisation and result-view types, keeping them cleanly separate from the human-facing display layer.
  • resolveRemoveSelectors centralises selector resolution for both the JSON and CLI remove paths, giving the JSON path atomic "all or nothing" semantics (any ambiguous or missing selector returns a structured error before any deletion occurs).
  • ForegroundUsageOutcome gains method and received_snapshot fields and ForegroundUsageWorkerResult gains a requested flag, enabling the JSON output to expose full refresh provenance (source, method, status, http_status, error_code) per account.

Confidence Score: 5/5

Safe to merge — the JSON path is fully additive and the existing CLI paths are unchanged except for a refactor of selector resolution and plan-type normalisation that is well-covered by the expanded test suite.

All three JSON workflows use careful errdefer chains and ownership flags to prevent leaks. The schema migration logic is gated cleanly on schema_version and the enum rename (team→business, +go) propagates consistently through parse, storage, auth, session, and api layers. No data-loss or incorrect-state scenarios were found in normal or error paths.

No files require special attention. The two P2 observations (warnings not serialised, usageSource triple-maps to cache) are documentation/design clarification points rather than defects.

Important Files Changed

Filename Overview
src/cli/json_output.zig New file: 316-line JSON serializer for list/switch/remove results and structured error types. Well-structured with separate write/print pairs and a private schema_version constant (1) independent of registry schema.
src/workflows/results.zig New file: 451-line result type definitions (ListResult, SwitchResult, RemoveResult) with careful errdefer chains throughout. buildAccountViewForKey correctly uses allocator.free(views) to release only the backing array while transferring the single AccountView's inner allocations to the caller.
src/workflows/remove.zig Major extension: adds handleRemoveJson and resolveRemoveSelectors. The selected_owned flag correctly guards the defer, and removed_views are captured before mutation so they correctly represent what was removed.
src/workflows/switch.zig Adds handleSwitchQueryJson with correct deferred cleanup. Asserts opts.json == false in handleSwitchPrevious to make the JSON/non-JSON dispatch explicit at call boundaries.
src/workflows/list.zig Refactored into computeListState + computeList + handleList. The ListResult.warnings field is built but routed to std.log.warn in JSON mode (not serialized into the JSON output); per-account refresh status covers the same data for JSON consumers.
src/registry/parse.zig parsePlanType replaced by normalizePlanType (live/API input) and parseStoredPlanType (registry read with schema_version gate). Schema < 4 delegates to normalizePlanType for migration; schema 4 uses strict matching only.
src/registry/common.zig PlanType enum drops .team and adds .go; planLabel correctly maps .business → "Business" (formerly .team).
src/registry/account_ops.zig isTeamAccount renamed to isWorkspaceAccount, now includes .edu and .enterprise alongside .business. findAccountIndexByAccountKey signature changed to *const Registry.
src/workflows/usage.zig Adds UsageRefreshMethod enum and requested field; local-only refresh now populates per-account outcome structs matching the API path. LocalUsageRefreshResult enum cleanly replaces the previous bool return.
src/cli/commands/remove.zig Adds --json flag parsing with selectors_transferred ownership flag. Validates that --json requires explicit selectors or --all.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant CLI as CLI (commands/*.zig)
    participant Root as workflows/root.zig
    participant WF as workflow (list/switch/remove)
    participant Reg as registry
    participant JSON as cli/json_output.zig
    participant Results as workflows/results.zig

    CLI->>Root: "parse() → Command{json:true}"
    Root->>Root: commandWantsJson() → true
    Root->>Reg: resolveCodexHome() [error→printJsonStartupError]
    Root->>WF: "handleList/Switch/Remove(opts{json:true})"

    alt list --json
        WF->>WF: computeListState()
        WF->>Reg: loadRegistry, syncActive, refreshUsage
        WF->>Results: buildListResult(reg, usage_state)
        Results->>Results: buildAccountViewsForIndices
        Results-->>WF: ListResult
        WF->>JSON: printListResult(result)
        JSON-->>CLI: stdout JSON
    else switch query --json
        WF->>Reg: loadRegistry, syncActive
        WF->>Reg: resolveSwitchQueryLocally(query)
        alt not_found / multiple
            WF->>JSON: printError(account_not_found or ambiguous_query)
        else direct
            WF->>Reg: activateAccountByKey + saveRegistry
            WF->>Results: buildSwitchResult(reg, account_key)
            Results-->>WF: SwitchResult
            WF->>JSON: printSwitchResult(result)
        end
        JSON-->>CLI: stdout JSON
    else remove selectors --json
        WF->>Reg: loadRegistry, syncActive
        WF->>WF: resolveRemoveSelectors(selectors)
        alt hasNotFound or hasAmbiguous
            WF->>Results: buildSelectorResolutionViews
            WF->>JSON: printSelectorResolutionError
        else all resolved
            WF->>Results: buildAccountViewsForIndices (snapshot before removal)
            WF->>Reg: removeSelectedAccountsAndPersist
            WF->>JSON: printRemoveResult(result)
        end
        JSON-->>CLI: stdout JSON
    end
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant CLI as CLI (commands/*.zig)
    participant Root as workflows/root.zig
    participant WF as workflow (list/switch/remove)
    participant Reg as registry
    participant JSON as cli/json_output.zig
    participant Results as workflows/results.zig

    CLI->>Root: "parse() → Command{json:true}"
    Root->>Root: commandWantsJson() → true
    Root->>Reg: resolveCodexHome() [error→printJsonStartupError]
    Root->>WF: "handleList/Switch/Remove(opts{json:true})"

    alt list --json
        WF->>WF: computeListState()
        WF->>Reg: loadRegistry, syncActive, refreshUsage
        WF->>Results: buildListResult(reg, usage_state)
        Results->>Results: buildAccountViewsForIndices
        Results-->>WF: ListResult
        WF->>JSON: printListResult(result)
        JSON-->>CLI: stdout JSON
    else switch query --json
        WF->>Reg: loadRegistry, syncActive
        WF->>Reg: resolveSwitchQueryLocally(query)
        alt not_found / multiple
            WF->>JSON: printError(account_not_found or ambiguous_query)
        else direct
            WF->>Reg: activateAccountByKey + saveRegistry
            WF->>Results: buildSwitchResult(reg, account_key)
            Results-->>WF: SwitchResult
            WF->>JSON: printSwitchResult(result)
        end
        JSON-->>CLI: stdout JSON
    else remove selectors --json
        WF->>Reg: loadRegistry, syncActive
        WF->>WF: resolveRemoveSelectors(selectors)
        alt hasNotFound or hasAmbiguous
            WF->>Results: buildSelectorResolutionViews
            WF->>JSON: printSelectorResolutionError
        else all resolved
            WF->>Results: buildAccountViewsForIndices (snapshot before removal)
            WF->>Reg: removeSelectedAccountsAndPersist
            WF->>JSON: printRemoveResult(result)
        end
        JSON-->>CLI: stdout JSON
    end
Loading

Reviews (3): Last reviewed commit: "docs: streamline JSON API guidance" | Re-trigger Greptile

Comment thread src/workflows/switch.zig Outdated
Comment thread src/workflows/results.zig Outdated
Comment thread src/registry/account_ops.zig
@Loongphy

Copy link
Copy Markdown
Owner Author

@greptile review

@Loongphy
Loongphy marked this pull request as ready for review July 18, 2026 13:11
@Loongphy Loongphy changed the title feat: add JSON API mode for account workflows feat: support --json Jul 18, 2026
@Loongphy
Loongphy merged commit 4a8a5c0 into main Jul 18, 2026
13 checks passed
@Loongphy
Loongphy deleted the agent/json-api-mode branch July 18, 2026 13:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant